<?php

namespace Kunfeng\Dify\Client\Impl;

use Kunfeng\Dify\Client\DifyChatflowClientInterface;
use Kunfeng\Dify\Callback\ChatStreamCallback;
use Kunfeng\Dify\Constants\ApiPaths;
use GuzzleHttp\Exception\GuzzleException;
use Kunfeng\Dify\Model\Chat\ChatMessage;
use Kunfeng\Dify\Model\Chat\ChatMessageResponse;
use Kunfeng\Dify\Model\Chat\MessageListResponse;
use Kunfeng\Dify\Model\Chat\ConversationListResponse;
use Kunfeng\Dify\Model\Chat\Conversation;
use Kunfeng\Dify\Model\Chat\SuggestedQuestionsResponse;
use Kunfeng\Dify\Model\Chat\AudioToTextResponse;
use Kunfeng\Dify\Model\Chat\AnnotationListResponse;
use Kunfeng\Dify\Model\Chat\AnnotationReply;
use Kunfeng\Dify\Model\Chat\VariableResponse;
use Kunfeng\Dify\Model\Common\SimpleResponse;
use Kunfeng\Dify\Model\File\FileUploadRequest;
use Kunfeng\Dify\Model\File\FileUploadResponse;
use Kunfeng\Dify\Model\File\FilePreviewResponse;
use Kunfeng\Dify\Model\Chat\AppInfoResponse;
use Kunfeng\Dify\Model\Chat\AppParametersResponse;
use Kunfeng\Dify\Model\Chat\AppWebAppSettingResponse;

/**
 * Dify 工作流编排对话型应用客户端实现
 */
class DifyChatflowClient extends AbstractDifyClient implements DifyChatflowClientInterface
{
    public function __construct(string $baseUrl, string $apiKey, $httpClient = null, $retryHandler = null)
    {
        parent::__construct($baseUrl, $apiKey, $httpClient, $retryHandler);
    }

    /**
     * 发送工作流编排对话消息（阻塞模式）
     */
    public function sendChatMessage(ChatMessage $message): ChatMessageResponse
    {
        $messageData = $message->toArray();
        $data = $this->executePost(ApiPaths::CHAT_MESSAGES, $messageData);
        return ChatMessageResponse::fromArray($data);
    }

    /**
     * 发送工作流编排对话消息（流式模式）
     */
    public function sendChatMessageStream(ChatMessage $message, ChatStreamCallback $callback): void
    {
        $messageData = $message->toArray();
        
        try {
            $response = $this->httpClient->request('POST', $this->baseUrl . ApiPaths::CHAT_MESSAGES, [
                'json' => $messageData,
                'stream' => true,
                'headers' => [
                    'Accept' => 'text/event-stream',
                ]
            ]);
            $this->processStreamResponse($response, $callback);
        } catch (\Throwable $e) {
            $callback->handleException($e);
        }
    }

    /**
     * 获取消息列表
     */
    public function getMessages(string $conversationId, string $user, ?string $firstId = null, ?int $limit = null): MessageListResponse
    {
        $query = [
            'conversation_id' => $conversationId,
            'user' => $user,
        ];
        
        if ($firstId !== null) {
            $query['first_id'] = $firstId;
        }
        if ($limit !== null) {
            $query['limit'] = $limit;
        }

        $data = $this->executeGet(ApiPaths::MESSAGES, $query);
        return MessageListResponse::fromArray($data);
    }

    /**
     * 获取会话列表
     */
    public function getConversations(string $user, ?string $firstId = null, ?int $limit = null, ?string $pinned = null): ConversationListResponse
    {
        $query = ['user' => $user];
        
        if ($firstId !== null) {
            $query['first_id'] = $firstId;
        }
        if ($limit !== null) {
            $query['limit'] = $limit;
        }
        if ($pinned !== null) {
            $query['pinned'] = $pinned;
        }

        $data = $this->executeGet(ApiPaths::CONVERSATIONS, $query);
        return ConversationListResponse::fromArray($data);
    }

    /**
     * 重命名会话
     */
    public function renameConversation(string $conversationId, string $name, bool $autoGenerate = false, ?string $user = null): Conversation
    {
        $data = $this->executePost(ApiPaths::CONVERSATIONS . '/' . $conversationId . ApiPaths::NAME, [
            'name' => $name,
            'auto_generate' => $autoGenerate,
            'user' => $user
        ]);
        return Conversation::fromArray($data);
    }

    /**
     * 删除会话
     */
    public function deleteConversation(string $conversationId, string $user): SimpleResponse
    {
        $data = $this->executeDelete(ApiPaths::CONVERSATIONS . '/' . $conversationId, [
            'user' => $user
        ]);
        return SimpleResponse::fromArray($data);
    }

    /**
     * 发送消息反馈
     */
    public function feedbackMessage(string $messageId, string $rating, string $user, ?string $comment = null): SimpleResponse
    {
        $data = $this->executePost(ApiPaths::FEEDBACKS, [
            'message_id' => $messageId,
            'rating' => $rating,
            'user' => $user,
            'comment' => $comment
        ]);
        return SimpleResponse::fromArray($data);
    }

    /**
     * 获取建议问题
     */
    public function getSuggestedQuestions(string $messageId, string $user): SuggestedQuestionsResponse
    {
        $data = $this->executeGet(ApiPaths::SUGGESTED_QUESTIONS, [
            'message_id' => $messageId,
            'user' => $user
        ]);
        return SuggestedQuestionsResponse::fromArray($data);
    }

    /**
     * 语音转文字
     */
    public function audioToText($file, string $user): AudioToTextResponse
    {
        $multipart = [
            [
                'name' => 'file',
                'contents' => $file
            ],
            [
                'name' => 'user',
                'contents' => $user
            ]
        ];

        $response = $this->httpClient->request('POST', $this->baseUrl . ApiPaths::AUDIO_TO_TEXT, [
            'multipart' => $multipart
        ]);
        
        $data = $this->handleResponse($response);
        return AudioToTextResponse::fromArray($data);
    }

    /**
     * 文字转语音
     */
    public function textToAudio(?string $messageId = null, ?string $text = null, ?string $user = null): string
    {
        $data = [];
        if ($messageId !== null) {
            $data['message_id'] = $messageId;
        }
        if ($text !== null) {
            $data['text'] = $text;
        }
        if ($user !== null) {
            $data['user'] = $user;
        }

        $response = $this->httpClient->request('POST', $this->baseUrl . ApiPaths::TEXT_TO_AUDIO, [
            'json' => $data
        ]);
        
        return $response->getBody()->getContents();
    }

    /**
     * 获取标注列表
     */
    public function getAnnotations(string $messageId, string $user): AnnotationListResponse
    {
        $data = $this->executeGet(ApiPaths::APPS_ANNOTATIONS, [
            'message_id' => $messageId,
            'user' => $user
        ]);
        return AnnotationListResponse::fromArray($data);
    }

    /**
     * 回复标注
     */
    public function replyAnnotation(string $messageId, string $annotationId, AnnotationReply $reply, string $user): SimpleResponse
    {
        $data = $this->executePost(ApiPaths::APPS_ANNOTATIONS_REPLY, [
            'message_id' => $messageId,
            'annotation_id' => $annotationId,
            'answer' => $reply->getAnswer(),
            'user' => $user
        ]);
        return SimpleResponse::fromArray($data);
    }

    /**
     * 获取应用变量
     */
    public function getAppVariables(): VariableResponse
    {
        $data = $this->executeGet(ApiPaths::META . '/variables');
        return VariableResponse::fromArray($data);
    }

    // 实现 DifyBaseClientInterface 方法
    public function uploadFile($fileOrRequest, $filePathOrStream, ?string $user = null): FileUploadResponse
    {
        return parent::uploadFile($fileOrRequest, $filePathOrStream, $user);
    }

    public function getAppInfo(): AppInfoResponse
    {
        $data = $this->executeGet(ApiPaths::META);
        return AppInfoResponse::fromArray($data);
    }

    public function getAppParameters(): AppParametersResponse
    {
        $data = $this->executeGet(ApiPaths::META . '/parameters');
        return AppParametersResponse::fromArray($data);
    }

    public function getAppWebAppSettings(): AppWebAppSettingResponse
    {
        $data = $this->executeGet(ApiPaths::META . '/webapp-settings');
        return AppWebAppSettingResponse::fromArray($data);
    }

    public function previewFile(string $fileId, bool $asAttachment = false): FilePreviewResponse
    {
        $data = $this->executeGet(ApiPaths::FILES_PREVIEW . '/' . $fileId, [
            'as_attachment' => $asAttachment
        ]);
        return FilePreviewResponse::fromArray($data);
    }

    public function close(): void
    {
        // 关闭 HTTP 客户端连接
    }

    /**
     * 处理流式响应
     */
    private function processStreamResponse($response, ChatStreamCallback $callback): void
    {
        $body = $response->getBody();
        
        while (!$body->eof()) {
            $line = $body->readLine();
            if (empty(trim($line))) {
                continue;
            }

            if (strpos($line, 'data: ') === 0) {
                $data = substr($line, 6);
                if ($data === '[DONE]') {
                    break;
                }

                $eventData = json_decode($data, true);
                if ($eventData) {
                    $this->handleStreamEvent($eventData, $callback);
                }
            }
        }
    }

    /**
     * 处理流式事件
     */
    private function handleStreamEvent(array $eventData, ChatStreamCallback $callback): void
    {
        $eventType = $eventData['event'] ?? '';
        
        switch ($eventType) {
            case 'message':
                $callback->handleMessage(\Kunfeng\Dify\Event\MessageEvent::fromArray($eventData));
                break;
            case 'message_end':
                $callback->handleMessageEnd(\Kunfeng\Dify\Event\MessageEndEvent::fromArray($eventData));
                break;
            case 'message_file':
                $callback->handleMessageFile(\Kunfeng\Dify\Event\MessageFileEvent::fromArray($eventData));
                break;
            case 'message_replace':
                $callback->handleMessageReplace(\Kunfeng\Dify\Event\MessageReplaceEvent::fromArray($eventData));
                break;
            case 'agent_message':
                $callback->handleAgentMessage(\Kunfeng\Dify\Event\AgentMessageEvent::fromArray($eventData));
                break;
            case 'agent_thought':
                $callback->handleAgentThought(\Kunfeng\Dify\Event\AgentThoughtEvent::fromArray($eventData));
                break;
            case 'tts_message':
                $callback->handleTtsMessage(\Kunfeng\Dify\Event\TtsMessageEvent::fromArray($eventData));
                break;
            case 'tts_message_end':
                $callback->handleTtsMessageEnd(\Kunfeng\Dify\Event\TtsMessageEndEvent::fromArray($eventData));
                break;
            case 'error':
                $callback->handleError(\Kunfeng\Dify\Event\ErrorEvent::fromArray($eventData));
                break;
            case 'ping':
                $callback->handlePing(\Kunfeng\Dify\Event\PingEvent::fromArray($eventData));
                break;
        }
    }
}
